package com.hamishmedlin.d64pw;

public class QEncoder {
	
	public static String encodePassword(Fields fields){
		int[] encode = new int[10];
		int i;
		int bit = 0;
		int decodebit[] = new int[3];
		int passBit = 0;
		int xbit1 = 8;
		int xbit2 = 0;
		//int xbit3 = 0;
		
		for(i = 0;i < 10;i++){
			encode[i] = 0;
		}
		
		for(i = 0;i < 16;i++){
			QGlobals.passwordData[i] = 0;
		}
		
		// map and skill
		int nextmap = fields.getNextMap();
		int gameskill = fields.getGameSkill();
		
		encode[0] = (((nextmap & 0x3f) << 2) & 0xff) | (gameskill & 3);
		
		//weapons
		
		for(i = 0;i < QGlobals.numWeapons;i++){
			if(!QGlobals.weaponControlForIndex[i].equals(QGlobals.WEAPON_FIST) && !QGlobals.weaponControlForIndex[i].equals(QGlobals.WEAPON_PISTOL)){
				String weapon = QGlobals.weaponControlForIndex[i];
				boolean weaponowned = fields.getChecked(weapon);
				if(weaponowned){
					encode[1] |= 1 << bit;
					encode[1] = encode[1] & 0xff;
				}
				++bit;
			}
		}
		
		// backpack
		if(fields.getBackback()){
			encode[5] |= 0x80;
		}
		bit = 0;
		
		//clip
		bit = encodePassItem(fields.getClip(), fields.getMaxClip());
		encode[2] = (bit << 4) & 0xff;
		
		
		//shell
		bit = encodePassItem(fields.getShells(), fields.getMaxShell());
		encode[2] |= bit & 0xff;
		
		//cell
		bit = encodePassItem(fields.getCells(), fields.getMaxCell());
		encode[3] = (bit << 4) & 0xff;
		
		//rocket
		bit = encodePassItem(fields.getRockets(), fields.getMaxRocket());
		encode[3] |= bit & 0xff;
		
		//health
		bit = encodePassItem(fields.getHealth(), 200);
		encode[4] = bit << 4;
		
		//armor
		bit = encodePassItem(fields.getArmor(), 200);
		encode[4] |= bit;
		
		//armortype
		encode[5] |= fields.getArmorType();
		
		int artifacts = 0;
		if(fields.getChecked(QGlobals.ARTIFACT_FAST)){
			++artifacts;
		}
		
		if(fields.getChecked(QGlobals.ARTIFACT_DOUBLE)){
			++artifacts;
		}
		
		if(fields.getChecked(QGlobals.ARTIFACT_TRIPLE)){
			++artifacts;
		}
		
		encode[5] |= artifacts << 2;
		
		
		
		//encoding
		decodebit[0] = QUtils.makeBE16(encode[0], encode[1]);
		decodebit[1] = QUtils.makeBE16(encode[2], encode[3]);
		decodebit[2] = QUtils.makeBE16(encode[4], encode[5]);
				
		int dec1 = QUtils.byteSwap(~(decodebit[0] + decodebit[1] + decodebit[2]));
		int dec2 = QUtils.byteSwap(~(decodebit[0] ^ decodebit[1] ^ decodebit[2]));
		
		
		int[] dec1Exp = QUtils.unmakeBE16(dec1);
		int[] dec2Exp = QUtils.unmakeBE16(dec2);
		
		encode[6] = dec1Exp[0];
		encode[7] = dec1Exp[1];
		encode[8] = dec2Exp[0];
		encode[9] = dec2Exp[1];
		
		for(i = 0; i < 10; i++){
		    bit = encode[QGlobals.passwordTable[i]];
		    encode[i] = encode[i] ^ bit;
		}
		
		bit = 0;
		
		while(bit < 0x50){
			passBit = 0;
			
			CheckPassCodeHolder rets1 = checkPassCode(bit, xbit2, encode);

			bit = rets1.getValue(1);
		    xbit2 = rets1.getValue(2);
		    //xbit3 = rets1.getValue(3);
		    if(rets1.getCheck()){
		    	passBit = 16;
		    }
		    
		    xbit1 = 8;
		    ++bit;
		    
		    for(i=0;i<4;i++){
		    	CheckPassCodeHolder rets2 = checkPassCode(bit, xbit2, encode);
		    	bit = rets2.getValue(1);
		    	xbit2 = rets2.getValue(2);
		    	//xbit3 = rets2.getValue(3);
		    	
		    	if(rets2.getCheck()){
		    		passBit |= xbit1;
		    	}
		    	
		    	xbit1 >>= 1;
		    	++bit;
		    }
		    QGlobals.passwordData[QUtils.intDivide(bit-1, 5)] = passBit;
		}
		
		return displayPassword();
	}

	private static String displayPassword(){		
		String outputStr = "";
		int i;
		int pdidx = 0;
		
		for(i = 0; i < 19; i++){
			if(i == 4 || i == 9 || i == 14){
				outputStr += " ";
			}else{
				int tmp = QGlobals.passwordData[pdidx];
				if(tmp == 0xff){
					outputStr += " ";
				}else{
					outputStr += QGlobals.passwordChar.charAt(tmp);
				}
				++pdidx;
			}
		}
		return outputStr.toUpperCase();
	}
	
	private static int encodePassItem(int value,int maxvalue){
		int bit;
		value = value << 3;
		bit = QUtils.intDivide(value, maxvalue);
		
		if(QUtils.intMod(value, maxvalue)!= 0){
			bit++;
		}
		
		return bit;
	}
	
	public static CheckPassCodeHolder checkPassCode(int bit1,int bit2,int[] encode){
		int bit3;
		int checkByte = 0;
		
		CheckPassCodeHolder result = new CheckPassCodeHolder();
		
		if(bit1 < 0){
			bit2 = (bit1 + 7) >> 3;
		}else{
			bit2 = bit1 >> 3;
		}
				
		bit3 = bit1 & 7;		;
		if(bit1 < 0){
			if(bit3 != 0){
				bit3 -= 7;
			}
		}		
		checkByte = encode[bit2];
		
		if((checkByte & (0x80 >> bit3)) != 0){
			result.setChecked(true);
		}
		
		result.setValue(1, bit1);
		result.setValue(2, bit2);
		result.setValue(3, bit3);
		
		return result;
	}
}
